package pers.cz.thread;

import pers.cz.exception.ErrorCode;
import pers.cz.exception.JefFlowException;
import pers.cz.flowcell.JefFlowCell;
import pers.cz.node.Node;
import pers.cz.node.NodeCallBack;
import pers.cz.node.NodeRunState;
import pers.cz.node.NodeEnum;
import pers.cz.utils.LogUtils;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;

/**
 * @program: Reids
 * @description: 流程执行器
 * @author: Cheng Zhi
 * @create: 2023-01-09 10:52
 **/
public class JefFlowAutoExcutor {

    /**
     * 全局锁, 用于控制多个上游节点公用一个下游节点的情况，保证下游节点只运行一次
     */
    private CountDownLatch latch;

    public void start(JefFlowCell jefFlowCell,String folwId) {

        this.run(jefFlowCell, folwId);

    }

    public void run(JefFlowCell jefFlowCell, String folwId) {

        Node node = getNodeInstance(jefFlowCell);
        LogUtils.debug(node.getName() + "即将运行" + Thread.currentThread().getName());
        node.run(new NodeCallBack() {
            @Override
            public void callBack(Map<String,Object> paramsMap) {
                // 执行下一个时先等待一下，防止初始化工作没有完成
                // 1标识成功，2标识执行失败
                if (paramsMap.get(NodeRunState.RUN_TYPE).equals(NodeRunState.RUN_SUCCESS)) {
                    runNext(jefFlowCell.hasNext() ? jefFlowCell.getNextCell() : new ArrayList<JefFlowCell>(), paramsMap, folwId);
                }

            }
        });
    }

    public void runNext(List<JefFlowCell> jefFlowCells, Map<String,Object> paramsMap, String folwId) {

        // 串行
        int size = jefFlowCells.size();
        if (size > 0 && size == 1) {
            JefFlowCell jefFlowCell = jefFlowCells.get(0);
            jefFlowCell.setParams(paramsMap); // 设置自定义参数
            if (!hasManyUpstream(jefFlowCell, folwId)) {
                run(jefFlowCell,folwId);
            }
            return;
        }

        // 多个下游节点需要并行运行
        for (JefFlowCell mxCell : jefFlowCells) {
            mxCell.setParams(paramsMap); // 设置自定义参数
            // 如果节点具有多个上游，要等待所有上游执行完成，再执行，且只执行一次
            if (!hasManyUpstream(mxCell, folwId)) {
                JefFlowAutoThreadPool.getThreadPool(folwId).execute(() -> {
                    run(mxCell, folwId);
                });
            }
        }

    }

    /**
     * 处理节点具有多个上游节点的情况。
     * @param jefFlowCell
     * @param folwId
     * @return
     */
    private boolean hasManyUpstream(JefFlowCell jefFlowCell, String folwId) {
        if (jefFlowCell.hasManyUpstreamMode()) {
            List<Integer> upstreamNode = jefFlowCell.getUpstreamNode();
            LogUtils.debug(jefFlowCell.getName() + "具有多个上游节点,节点个数为：" + upstreamNode.size());
            if (latch == null || latch.getCount() == 0) {
                latch = new CountDownLatch(upstreamNode.size());
            }

            latch.countDown();
            long count = latch.getCount();
            if (count == 0) {
                run(jefFlowCell, folwId);
                // 运行过之后，就要把锁消耗完
                while(latch.getCount() > 0) {
                    latch.countDown();
                }
            }

            return true;
        }

        return false;
    }
    private Node getNodeInstance(JefFlowCell jefFlowCell) {

        String name = jefFlowCell.getFlowNodeName();
        Class<? extends Node> nodeClassByNodeName = NodeEnum.getNodeClassByNodeName(name);
        Node node = null;
        try {
            node = nodeClassByNodeName.getConstructor(JefFlowCell.class).newInstance(jefFlowCell);
        } catch (Exception e) {
            //e.printStackTrace();
            throw new JefFlowException(ErrorCode.JEF_FLOW_NODE_IMPL_IS_NULL_ERROR, name);
        }

        return node;
    }
}
